use std::io;
use std::net::SocketAddr;
use std::sync::Arc;
use async_trait::async_trait;
use tokio::net::UdpSocket;
use tokio::runtime::Runtime;
use tokio::sync::mpsc;
use crate::serializer::serialization::Serialized;
use crate::start::dispatcher::PacketDispatcher;
use crate::start::processor::Processor;
use crate::start::SendMsg;
use crate::start::udp::UdpProcessor;

pub struct TcpClient;

pub struct UdpClient{

}

#[async_trait]
pub trait Client {
    type Socket;

    async fn connect(address: SocketAddr) -> io::Result<Self::Socket>;
    async fn send_msg<T: Serialized+Send>(&self,cmd: i16, send_msg: SendMsg<T>);
    async fn send_msg_to<T: Serialized+Send>(&self, cmd: i16, send_msg: SendMsg<T>, address: SocketAddr);

    async fn poll( socket: Self::Socket, service: Arc<PacketDispatcher>);
}

#[async_trait]
impl Client for UdpClient {
    type Socket = UdpSocket;

    async fn connect(address: SocketAddr) -> io::Result<Self::Socket> {
        let local_addr: SocketAddr = if address.is_ipv4() {
            "0.0.0.0:0"
        } else {
            "[::]:0"
        }
            .parse().unwrap();

        let socket = UdpSocket::bind(local_addr).await?;
        socket.connect(address).await?;
        return Ok(socket);
    }

    async fn send_msg<T: Serialized+Send>(&self, cmd: i16, send_msg: SendMsg<T>) {

    }

    async fn send_msg_to<T: Serialized+Send>(&self, cmd: i16, send_msg: SendMsg<T>, address: SocketAddr) {
        todo!()
    }

    async fn poll( socket: Self::Socket, service: Arc<PacketDispatcher>) {
        let (send, mut recv) = mpsc::unbounded_channel();
        let mut processor = UdpProcessor {
            send: send,
            recv: Some(recv),
        };
        processor.poll(socket, service).await;
    }
}


